4  Polimorfismo

4.1 Binding dinamico

Quando un linguaggio supporta il late binding, ci deve essere un meccanismo che determina a run-time il tipo dell’oggetto passato e selezionare di conseguenza il metodo appropriato. Il meccanismo di late-binding varia da linguaggio a linguaggio. In Java tale meccanismo è impostato per default a meno che non si dichiara esplicitamente un metodo con la parola chiave final. Un’altra eccezione è rappresentata dai metodi static per i quali vale il binding statico.

4.2 Classe astratta

Quando si definisce una classe astratta, tutti i metodi delle classi da essa derivate, la cui dichiarazione corrisponde con quelli della classe astratta, sono invocati mediante il meccanismo di binding dinamico.

Visto che una classe astratta esprime solo l’interfaccia e non una particolare implementazione, ha senso non istanziarla.

Java fornisce la parola chiave abstract per indicare che una classe o un metodo sono astratti.

E’ possibile anche avere classi astratte che non contengono alcun metodo astratto, per esempio classi di cui non si desidera alcuna istanza.

4.3 Costruttori e polimorfismo

Il processo di inizializzazione è il seguente:

  • La memoria allocata per l’oggetto è inizializzata a zero binario prima che accada tutto il resto

  • Sono invocati i costruttori della classe base

  • I membri sono inizializzati nell’ordine di dichiarazione

  • Viene invocato il corpo del costruttore della classe derivata

Esempio:

abstract class Glyph {
    abstract void draw();
    
    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}
class RoundGlyph extends Glyph {
    int radius = 1;
    
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    }
    
    void draw() {
        System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
} 

public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}
   
/* Output:
    Glyph() before draw()
    RoundGlyph.draw(), radius = 0
    Glyph() after draw()
    RoundGlyph.RoundGlyph(), radius = 5
*/